home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / gedit-2 / plugins / snippets / Parser.py < prev    next >
Encoding:
Python Source  |  2009-04-14  |  9.5 KB  |  260 lines

  1. #    Gedit snippets plugin
  2. #    Copyright (C) 2006-2007  Jesse van den Kieboom <jesse@icecrew.nl>
  3. #
  4. #    This program is free software; you can redistribute it and/or modify
  5. #    it under the terms of the GNU General Public License as published by
  6. #    the Free Software Foundation; either version 2 of the License, or
  7. #    (at your option) any later version.
  8. #
  9. #    This program is distributed in the hope that it will be useful,
  10. #    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. #    GNU General Public License for more details.
  13. #
  14. #    You should have received a copy of the GNU General Public License
  15. #    along with this program; if not, write to the Free Software
  16. #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17.  
  18. import os
  19. import re
  20. import sys
  21. from SubstitutionParser import SubstitutionParser
  22.  
  23. class Token:
  24.         def __init__(self, klass, data):
  25.                 self.klass = klass
  26.                 self.data = data
  27.  
  28.         def __str__(self):
  29.                 return '%s: [%s]' % (self.klass, self.data)
  30.                 
  31.         def __eq__(self, other):
  32.                 return self.klass == other.klass and self.data == other.data
  33.         
  34.         def __ne__(self, other):
  35.                 return not self.__eq__(other)
  36.  
  37. class Parser:
  38.         SREG_ENV = '[A-Z_]+'
  39.         SREG_ID = '[0-9]+'
  40.  
  41.         REG_ESCAPE = re.compile('(\\$(%s|\\(|\\{|<|%s)|`|\\\\)' % (SREG_ENV, SREG_ID))
  42.         
  43.         def __init__(self, **kwargs):
  44.                 for k, v in kwargs.items():
  45.                         setattr(self, k, v)
  46.  
  47.                 self.position = 0
  48.                 self.data_length = len(self.data)
  49.                 
  50.                 self.RULES = (self._match_env, self._match_regex, self._match_placeholder, self._match_shell, self._match_eval, self._text)
  51.         
  52.         def remains(self):
  53.                 return self.data[self.position:]
  54.  
  55.         def next_char(self):
  56.                 if self.position + 1 >= self.data_length:
  57.                         return ''
  58.                 else:
  59.                         return self.data[self.position + 1]
  60.                 
  61.         def char(self):
  62.                 if self.position >= self.data_length:
  63.                         return ''
  64.                 else:
  65.                         return self.data[self.position]
  66.  
  67.         def token(self):
  68.                 self.tktext = ''
  69.  
  70.                 while self.position < self.data_length:
  71.                         try:
  72.                                 # Get first character
  73.                                 func = {'$': self._rule,
  74.                                         '`': self._try_match_shell}[self.char()]
  75.                         except:
  76.                                 func = self._text
  77.  
  78.                         # Detect end of text token
  79.                         if func != self._text and self.tktext != '':
  80.                                 return Token('text', self.tktext)
  81.                         
  82.                         tk = func()
  83.  
  84.                         if tk:
  85.                                 return tk
  86.                 
  87.                 if self.tktext != '':
  88.                         return Token('text', self.tktext)
  89.  
  90.         def _need_escape(self):
  91.                 text = self.remains()[1:]
  92.  
  93.                 if text == '':
  94.                         return False
  95.                 
  96.                 return self.REG_ESCAPE.match(text)
  97.                 
  98.         def _escape(self):                
  99.                 if not self._need_escape():
  100.                         return
  101.                 
  102.                 # Increase position with 1
  103.                 self.position += 1
  104.                 
  105.         def _text(self):
  106.                 if self.char() == '\\':
  107.                         self._escape()
  108.  
  109.                 self.tktext += self.char()
  110.                 self.position += 1
  111.         
  112.         def _rule(self):
  113.                 for rule in self.RULES:
  114.                         res = rule()
  115.                         
  116.                         if res:
  117.                                 return res
  118.  
  119.         def _match_env(self):
  120.                 text = self.remains()
  121.                 match = re.match('\\$(%s)' % self.SREG_ENV, text) or re.match('\\${(%s)}' % self.SREG_ENV, text)
  122.                 
  123.                 if match:
  124.                         self.position += len(match.group(0))
  125.                         return Token('environment', match.group(1))
  126.         
  127.         def _parse_list(self, lst):
  128.                 pos = 0
  129.                 length = len(lst)
  130.                 items = []
  131.                 last = None
  132.                 
  133.                 while pos < length:
  134.                         char = lst[pos]
  135.                         next = pos < length - 1 and lst[pos + 1]
  136.                         
  137.                         if char == '\\' and (next == ',' or next == ']'):
  138.                                 char = next
  139.                                 pos += 1
  140.                         elif char == ',':
  141.                                 if last != None:
  142.                                         items.append(last)
  143.                                 
  144.                                 last = None
  145.                                 pos += 1
  146.                                 continue
  147.  
  148.                         last = (last != None and last + char) or char
  149.                         pos += 1
  150.                 
  151.                 if last != None:
  152.                         items.append(last)
  153.                 
  154.                 return items
  155.         
  156.         def _parse_default(self, default):
  157.                 match = re.match('^\\s*(\\\\)?(\\[((\\\\]|[^\\]])+)\\]\\s*)$', default)
  158.                 
  159.                 if not match:
  160.                         return [default]
  161.                 
  162.                 groups = match.groups()
  163.                 
  164.                 if groups[0]:
  165.                         return [groups[1]]
  166.  
  167.                 return self._parse_list(groups[2])
  168.         
  169.         def _match_placeholder(self):
  170.                 text = self.remains()
  171.                 
  172.                 match = re.match('\\${(%s)(:((\\\\\\}|[^}])+))?}' % self.SREG_ID, text) or re.match('\\$(%s)' % self.SREG_ID, text)
  173.                 
  174.                 if not match:
  175.                         return None
  176.                 
  177.                 groups = match.groups()
  178.                 default = ''
  179.                 tabstop = int(groups[0])
  180.                 self.position += len(match.group(0))
  181.                 
  182.                 if len(groups) > 1 and groups[2]:
  183.                         default = self._parse_default(groups[2].replace('\\}', '}'))
  184.  
  185.                 return Token('placeholder', {'tabstop': tabstop, 'default': default})
  186.  
  187.         def _match_shell(self):
  188.                 text = self.remains()
  189.                 match = re.match('`((%s):)?((\\\\`|[^`])+?)`' % self.SREG_ID, text) or re.match('\\$\\(((%s):)?((\\\\\\)|[^\\)])+?)\\)' % self.SREG_ID, text)
  190.                 
  191.                 if not match:
  192.                         return None
  193.                 
  194.                 groups = match.groups()
  195.                 tabstop = (groups[1] and int(groups[1])) or -1
  196.                 self.position += len(match.group(0))
  197.  
  198.                 if text[0] == '`':
  199.                         contents = groups[2].replace('\\`', '`')
  200.                 else:
  201.                         contents = groups[2].replace('\\)', ')')
  202.                 
  203.                 return Token('shell', {'tabstop': tabstop, 'contents': contents})
  204.  
  205.         def _try_match_shell(self):
  206.                 return self._match_shell() or self._text()
  207.         
  208.         def _eval_options(self, options):
  209.                 reg = re.compile(self.SREG_ID)
  210.                 tabstop = -1
  211.                 depend = []
  212.                 
  213.                 options = options.split(':')
  214.                 
  215.                 for opt in options:
  216.                         if reg.match(opt):
  217.                                 tabstop = int(opt)
  218.                         else:
  219.                                 depend += self._parse_list(opt[1:-1])
  220.                 
  221.                 return (tabstop, depend)
  222.                 
  223.         def _match_eval(self):
  224.                 text = self.remains()
  225.                 
  226.                 options = '((%s)|\\[([0-9, ]+)\\])' % self.SREG_ID
  227.                 match = re.match('\\$<((%s:)*)((\\\\>|[^>])+?)>' % options, text)
  228.                 
  229.                 if not match:
  230.                         return None
  231.                 
  232.                 groups = match.groups()
  233.                 (tabstop, depend) = (groups[0] and self._eval_options(groups[0][:-1])) or (-1, [])
  234.                 self.position += len(match.group(0))
  235.                 
  236.                 return Token('eval', {'tabstop': tabstop, 'dependencies': depend, 'contents': groups[5].replace('\\>', '>')})
  237.                 
  238.         def _match_regex(self):
  239.                 text = self.remains()
  240.                 
  241.                 content = '((?:\\\\[/]|\\\\}|[^/}])+)'
  242.                 match = re.match('\\${(?:(%s):)?\\s*(%s|\\$([A-Z_]+))?[/]%s[/]%s(?:[/]([a-zA-Z]*))?}' % (self.SREG_ID, self.SREG_ID, content, content), text)
  243.                 
  244.                 if not match:
  245.                         return None
  246.                 
  247.                 groups = match.groups()
  248.                 tabstop = (groups[0] and int(groups[0])) or -1
  249.                 inp = (groups[2] or (groups[1] and int(groups[1]))) or ''
  250.                 
  251.                 pattern = re.sub('\\\\([/}])', '\\1', groups[3])
  252.                 substitution = re.sub('\\\\([/}])', '\\1', groups[4])
  253.                 modifiers = groups[5] or ''
  254.                 
  255.                 self.position += len(match.group(0))
  256.                 
  257.                 return Token('regex', {'tabstop': tabstop, 'input': inp, 'pattern': pattern, 'substitution': substitution, 'modifiers': modifiers})
  258.  
  259. # ex:ts=8:et:
  260.